package com.chaihu.utils.util;


import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;


public class ConvertUtil {

    /**
     * 方法用途: 对所有传入参数按照字段名的 ASCII 码从小到大排序（字典序），并且生成url参数串<br>
     * 实现步骤: <br>
     *
     * @param paraMap    要排序的Map对象
     * @param urlEncode  是否需要URLENCODE
     * @param keyToLower 是否需要将Key转换为全小写
     *                   true:key转化成小写，false:不转化
     * @return
     */
    public static String getSignContent(Map<String, String> paraMap, boolean urlEncode, boolean keyToLower) {
        String buff = "";
        Map<String, String> tmpMap = paraMap;
        try {
            List<Map.Entry<String, String>> infoIds = new ArrayList<Map.Entry<String, String>>(tmpMap.entrySet());
            // 对所有传入参数按照字段名的 ASCII 码从小到大排序（字典序）
            Collections.sort(infoIds, new Comparator<Map.Entry<String, String>>() {

                @Override
                public int compare(Map.Entry<String, String> o1, Map.Entry<String, String> o2) {
                    return (o1.getKey()).toString().compareTo(o2.getKey());
                }
            });
            // 构造URL 键值对的格式
            StringBuilder buf = new StringBuilder();
            for (Map.Entry<String, String> item : infoIds) {
                if (StringUtils.isNotBlank(item.getKey())) {
                    String key = item.getKey();
                    Object tmpVal = item.getValue();
                    String val = null;
                    if (tmpVal instanceof JSONArray) {
                        JSONArray jsonArr = (JSONArray) tmpVal;
                        val = jsonArr.toString();
                    } else if (tmpVal instanceof JSONObject) {
                        JSONObject jsonObj = (JSONObject) tmpVal;
                        val = jsonObj.toString();
                    } else {
                        val = (String) tmpVal;
                    }
                    if (val == null) {
                        val = "";
                    }
                    if (urlEncode) {
                        val = URLEncoder.encode(val, "utf-8");
                    }
                    if (keyToLower) {
                        buf.append(key.toLowerCase() + "" + val);
                    } else {
                        buf.append(key + "" + val);
                    }
                }

            }
            buff = buf.toString();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return buff;
    }

    /**
     * 方法用途: 对参数进行MD5签名<br>
     * 实现步骤: <br>
     *
     * @param signContent 要排序的Map对象
     * @param urlEncode   是否需要URLENCODE
     * @param keyToLower  是否需要将Key转换为全小写
     *                    true:key转化成小写，false:不转化
     * @param salt        加密盐
     * @param charset     字符集
     * @return
     */
    public static String signByMD5(Map<String, String> paraMap, boolean urlEncode, boolean keyToLower,
                                   String salt, String charset) {
        Map<String, String> tmpMap = paraMap;
        for (String key : paraMap.keySet()) {
            Object tmpVal = paraMap.get(key);
            if (tmpVal instanceof JSONArray) {
                JSONArray jsonArr = (JSONArray) tmpVal;
                for (int i = 0; i < jsonArr.size(); i++) {
                    JSONObject jsonObject = jsonArr.getJSONObject(i);
                    tmpMap = (Map) jsonObject;
                    signByMD5(tmpMap, urlEncode, keyToLower, salt, charset);
                }
            }
        }
        String signContent = getSignContent(paraMap, urlEncode, keyToLower);
        try {
            return DigestUtils.md5Hex((signContent + salt).getBytes(charset));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }
    }


    /**
     * 创建加密签名
     *
     * @param map
     * @param secretKey
     * @return
     */
    public static String createSign(Map<String, String> map, String secretKey) {
        String buffer = secretKey +
                getSignContent(map, false, false) +
                secretKey;
        return DigestUtils.md5Hex(buffer.getBytes(StandardCharsets.UTF_8)).toUpperCase();
    }

}
